/*
 * Flashlib - QB9 common Flash library
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.qb9.flashlib.display
{
	import com.qb9.flashlib.tasks.*;
	import com.qb9.flashlib.utils.DisplayUtil;
	
	import flash.display.MovieClip;

	/**
	 * Play a MovieClip in any frame rate (even in reverse!).
	 *
	 * <p>
	 * Note: this task controls the MovieClip timeline using gotoAndStop().
	 * <strong>This will only work for MovieClips with a single timeline.</strong>
	 * If the MovieClip contains other MovieClips with their own timeline, the
	 * results will be unexpected.
	 * </p>
	 *
	 * @see "examples/playMovieClip"
	 */
	public class PlayMovieClip extends Task
	{
		protected var mc:MovieClip;
		/** The controlled MovieClip instance. */
		public function get movieClip():MovieClip {return mc}
		protected var delay:uint;
		protected var _fps:Number;
		/** The playback speed (frames per second). */
		public function get fps():Number {return _fps}
		protected var currentFrame:uint;
		protected var accumulator:uint;
		/** Wether or not to dispose of the MovieClip once playback completes. */
		public var autoDispose:Boolean;
		/** Remaining amount of loops to be played. */
		public var remainingLoops:int;
		
		/**
		 * Create a PlayMovieClip task.
		 *
		 * @param mc The MovieClip instance to be controlled.
		 * @param fps Desired animation speed, in frames per second.
		 *            A negative value can be used for a reverse animation.
		 *            If set to 0 (the default), <code>mc.stage.frameRate</code> is used (the MovieClip must be in the display list).
		 * @param loops Amount of loops to play.  The task completes when all loops have played.
		 *              If set to 0 (the default), the MovieClip will loop infinitely and the task will never complete.
		 * @param autoDispose If set to true, the MovieClip will be automatically removed from the display list when the task completes.
		 */
		public function PlayMovieClip(mc:MovieClip, fps:Number = 0, loops:uint = 0, autoDispose:Boolean = false)
		{
			this.remainingLoops = loops;
			this.mc = mc;
			this.autoDispose = autoDispose;
			this.fps = fps || mc.stage.frameRate;
		}

		/** @private */
		public function set fps(value:Number):void
		{
			this._fps = value;
			this.delay = 1000.0 / Math.abs(value);
		}
		
		/** @inheritDoc */
		public override function clone():ITask
		{
			return new PlayMovieClip(mc, _fps, remainingLoops, autoDispose);
		}

		/** @inheritDoc */
		public override function start():void
		{
			currentFrame = 0;
			updateMC();
			super.start();
		}

		/** @inheritDoc */
		public override function update(milliseconds:uint):void
		{
			super.update(milliseconds);
			
			accumulator += milliseconds;
			if (accumulator < delay)
				return;
			
			var frames:uint = accumulator / delay;
			accumulator -= delay * frames;
			currentFrame += frames;
			updateLoops(currentFrame / mc.totalFrames);
			currentFrame %= mc.totalFrames;
			updateMC();
		}

		private function updateLoops(div:uint):void
		{
			if (remainingLoops <= 0) // infinite loop
				return;
			remainingLoops -= div;
			if (remainingLoops > 0)
				return;
			taskComplete();
			currentFrame = mc.totalFrames - 1;
		}

		protected function updateMC():void
		{
			mc.gotoAndStop(_fps > 0 ? currentFrame + 1 : mc.totalFrames - currentFrame)
		}

		/** @inheritDoc */
		protected override function taskComplete():void
		{
			if (autoDispose)
				DisplayUtil.dispose(mc);
			super.taskComplete();
		}
	}
}

